﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml.Serialization;
using System.IO;

namespace DELVE_GAME
{
    /*
     * Please note that the GameSettings class is also serializable
     */

    #region replay list

    [Serializable]
    public class ReplayManager
    {
        const string replayDirectory = "Content/Replays";
        const string managerFile = "replayList.xml";

        public List<ReplayTag> loggedGames;
        int currentSelection;

        public ReplayManager()
        {
            loggedGames = new List<ReplayTag>();
            currentSelection = 0;
        }

        public int numReplays() { return loggedGames.Count; }

        public void readFromFile()
        {
            string fileLoc = replayDirectory + "/" + managerFile;
            if (Directory.Exists(replayDirectory) && File.Exists(fileLoc))
            {
                ReplayManager newList = new ReplayManager();
                XmlSerializer serializer = new XmlSerializer(newList.GetType());
                FileStream xmlFileStream = File.Open(fileLoc, FileMode.Open);
                newList = (ReplayManager)serializer.Deserialize(xmlFileStream);
                xmlFileStream.Close();
                this.loggedGames = newList.loggedGames;
            }
            else writeToFile();
        }

        public void writeToFile()
        {
            string fileLoc = replayDirectory + "/" + managerFile;
            if(!Directory.Exists(replayDirectory)) Directory.CreateDirectory(replayDirectory);
            XmlSerializer serializer = new XmlSerializer(this.GetType());
            StreamWriter writer = new StreamWriter(fileLoc);
            serializer.Serialize(writer, this);
            writer.Close();
        }

        public void logGame(GameLog toLog)
        {
            ReplayTag newTag = new ReplayTag();
            string replayLocation = loggedGames.Count.ToString() + ".xml";
            newTag.fileName = replayLocation;
            newTag.settings = toLog.settings;

            replayLocation = replayDirectory + "/" + replayLocation;

            //Write new replay to file
            XmlSerializer serializer = new XmlSerializer(toLog.GetType());
            StreamWriter writer = new StreamWriter(replayLocation);
            serializer.Serialize(writer, toLog);
            writer.Close();
            loggedGames.Add(newTag);
            writeToFile();

        }

        public void selectReplay(int selection) { currentSelection = selection; }

        public GameLog getReplay()
        {
            GameLog thisLog = null;
            if (loggedGames.Count != 0)
            {
                ReplayTag tag = loggedGames[currentSelection];
                string replayLocation = replayDirectory + tag.fileName;
                thisLog = new GameLog();
                XmlSerializer serializer = new XmlSerializer(thisLog.GetType());
                FileStream xmlFileStream = File.Open(replayLocation, FileMode.Open);
                thisLog = (GameLog)serializer.Deserialize(xmlFileStream);
                xmlFileStream.Close();
            }
            else thisLog = null;
            return thisLog;
        }
    }

    [Serializable]
    public struct ReplayTag
    {
        public string fileName;
        public GameSettings settings;
    }

    #endregion

    #region game log

    enum ACTIONS
    {
        PLACE_BASES,
        UPGRADE,
        SEND_REQUEST,
        ACCEPT_REQUEST,
        BREAK_ALLIANCE,
        END_TURN
    }

    [SerializableAttribute]
    public class GameLog
    {
        public DateTime gameTime;
        public GameSettings settings;
        public List<Turn> turns;
        int latestTurn;

        public GameLog()
        {
            gameTime = DateTime.Now;
            this.turns = new List<Turn>();
            latestTurn = -1;
        }

        #region write elements

        public void addSettings(GameSettings gameSettings)
        {
            this.settings = gameSettings;
        }

        //Place a base
        public void addAction(int actIndex, Point location)
        {
            Action action = addAction();
            action.actionIndex = actIndex;
            action.location = location;
        }

        //Add an upgrade
        public void addAction(int actIndex, Point location, int upgrade)
        {
            Action action = addAction();
            action.actionIndex = actIndex;
            action.location = location;
            action.upgradeIndex = upgrade;
        }

        //Form, answer or break an alliance
        public void addAction(int actIndex, int playerIndex)
        {
            Action action = addAction();
            action.actionIndex = actIndex;
            action.playerIndex = playerIndex;
        }

        //End a turn
        public void addAction(int actIndex)
        {
            Action action = addAction();
            action.actionIndex = actIndex;
        }

        private Action addAction()
        {
            Action action = new Action();
            turns[latestTurn].actions.Add(action);
            return action;
        }

        public void addTurn(int playerNum)
        {
            Turn turn = new Turn();
            turn.playerIndex = playerNum;
            addTurn(turn);
        }

        public void addTurn(Turn turn)
        {
            turns.Add(turn);
            latestTurn++;
        }

        #endregion

        #region read elements

        public void openForReading()
        {
            latestTurn = 0;
            turns[latestTurn].openForReading();
        }

        public Action performLatestAction()
        {
            Action latest = turns[latestTurn].readLatest();
            if (latest.getActionIndex() == (int)ACTIONS.END_TURN)
            {
                latestTurn++;
                if (latestTurn < turns.Count)
                {
                    turns[latestTurn].openForReading();
                }
            }
            return latest;
        }

        public Turn getLastTurn()
        {
            return turns[latestTurn];
        }

        public Action getLastAction()
        {
            Action last = null;
            last = turns[latestTurn].getLastAction();
            if (last == null && latestTurn > 0)
                last = turns[latestTurn - 1].getLastAction();
            return last;
        }

        #endregion

    }

    [SerializableAttribute]
    public class Turn
    {
        public int playerIndex;
        public List<Action> actions;
        [NonSerialized]
        int latestAction;

        public Turn()
        {
            this.actions = new List<Action>();
        }

        public void openForReading()
        {
            latestAction = 0;
        }

        public Action readLatest()
        {
            return actions[latestAction++];
        }

        public Action getLastAction()
        {
            Action last = null;
            if (latestAction > 0)
                last = actions[latestAction - 1];
            return last;
        }
    }

    [SerializableAttribute]
    public class Action
    {

        public int actionIndex;
        public Point location;
        public int upgradeIndex;
        public int playerIndex;

        public Action()
        {
            actionIndex = -1;
            actionIndex = -1;
            location = new Point(0, 0);
            upgradeIndex = -1;
            playerIndex = -1;
        }

        public int getActionIndex() { return actionIndex; }
        public Point getLocation() { return location; }
        public int getUpgradeType() { return upgradeIndex; }
        public int getPlayerIndex() { return playerIndex; }
    }
}

    #endregion
